package edu.udo.sopra10.chaturaji.ai;

import static edu.udo.sopra10.chaturaji.util.ExceptionUtil.assertNotNull;

import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;

import edu.udo.sopra10.chaturaji.entities.AbstractGame;
import edu.udo.sopra10.chaturaji.entities.Player;
import edu.udo.sopra10.chaturaji.entities.Square;
import edu.udo.sopra10.chaturaji.entities.coordinates.Position;
import edu.udo.sopra10.chaturaji.entities.pieces.DummyPiece;
import edu.udo.sopra10.chaturaji.entities.pieces.King;
import edu.udo.sopra10.chaturaji.entities.pieces.Pawn;
import edu.udo.sopra10.chaturaji.entities.pieces.Piece;
import edu.udo.sopra10.chaturaji.events.BoardResetEventListener;
import edu.udo.sopra10.chaturaji.events.MoveEvent;
import edu.udo.sopra10.chaturaji.events.MoveEventListener;
import edu.udo.sopra10.chaturaji.events.MoveRequestEventListener;
import edu.udo.sopra10.chaturaji.events.TurnRequestEventListener;
import edu.udo.sopra10.chaturaji.exceptions.NoPieceException;

public abstract class AbstractAI implements BoardResetEventListener, MoveEventListener, TurnRequestEventListener, MoveRequestEventListener {

	/**
	 * Eventlistener
	 */
	protected TurnRequestEventListener eventListener;

	/**
	 * A gameboard clone.
	 */
	protected Square[][] board;

	protected AIMoveTree aiMoveTree;

	/**
	 * The player which is represented by the AI.
	 */
	protected Player player;

	/**
	 * The pieces of the player.
	 */
	protected Collection<Piece> pieces;

	/**
	 * The current game.
	 */
	protected AbstractGame game;

	/**
	 * Checks if the specified piece is able to capture an opponents piece in
	 * one step.
	 * 
	 * @param piece
	 *            the specified piece.
	 * @return the position to a piece that can be captured. {@code null} if
	 *         there is no possible capture.
	 * 
	 */
	protected abstract Position getCaptureMove(Piece piece);

	/**
	 * @param piece
	 * @param position
	 *            the position of the piece.
	 * @return all pieces that can captured by the piece.
	 */
	protected Collection<Piece> getCaptureMoves(Piece piece, Position position) {
		board[piece.getSquare().getPosition().getX()][piece.getSquare()
				.getPosition().getY()].setPiece(null);
		board[position.getX()][position.getY()].setPiece(piece);

		Collection<Position> capturePositions = piece.getPossibleActions(board,
				position).getPossibleCaptures();
		LinkedList<Piece> capturePacies = new LinkedList<Piece>();

		for (Position item : capturePositions)
			capturePacies.add(game.getSquare(item).getPiece());
		if (capturePacies.isEmpty())
			return null;
		return capturePacies;
	}

	/**
	 * @param c
	 *            classtype of the piece. class of the piece
	 * @return the piece for the move.
	 * @throws NoPieceException
	 *             if the piece does not exists.
	 */
	protected Piece getPiece(Class<? extends Piece> c) throws NoPieceException {
		for (Piece item : pieces) {
			if (c.isInstance(item))
				return item;
		}
		throw new NoPieceException();
	}

	public Player getPlayer() {
		return player;
	}

	/**
	 * Returns a list of pieces that are able to capture a piece at the given
	 * position in one turn.
	 * 
	 * @param position position of the piece.
	 * @return a list of capturing pieces.
	 */
	protected List<Piece> getCapturingPieces ( Position position )
	{
		assertNotNull( position, "position" );
		
		Square[][] board = game.getBoard();
		Piece temporaryPiece = new DummyPiece( this.player, board[position.getX()][position.getY()] );;
		Piece originalPiece = board[position.getX()][position.getY()].getPiece();
		
		Piece piece;
		

		// set dummy
		board[position.getX()][position.getY()].setPiece( temporaryPiece );
		
		// check possible captures
		List<Piece> capturingPieces = new ArrayList<Piece>();
		for ( byte i = 0; i < 8; i++ )
		{
			for ( byte j = 0; j < 8; j++ )
			{
				piece = board[i][j].getPiece();
				
				if ( piece == null || piece.getOwner() == this.player )
					continue;
				
				if ( piece.getPossibleActions( board, board[i][j].getPosition() ).getPossibleCaptures().contains(
						position ) )
					capturingPieces.add( piece );
			}
		}
		
		// reset dummy
		board[position.getX()][position.getY()].setPiece( originalPiece );
		
		return capturingPieces;
	}

	public void setPlayer(Player player) {
		this.player = player;
	}
	
	protected LinkedList<Piece> getPieces() throws NoPieceException {
		LinkedList<Piece> pieces = new LinkedList<Piece>();
		for (Piece item : this.pieces) {
			if (Pawn.class.isInstance(item))
				pieces.add(item);
			if (King.class.isInstance(item))
				pieces.add(item);
		}
		if (pieces.isEmpty())
			throw new NoPieceException();
		return pieces;
	}
	
	public void onMoveEvent(MoveEvent event) {
	}
}